package com.cy.sys.Aop;


import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.cy.IPUtil;
import com.cy.sys.Aop.ancution.LoginObject;
import com.cy.sys.log.service.logService;
import com.cy.sys.pojo.SysLog;
import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.extern.slf4j.Slf4j;

@Aspect
@Component
@Slf4j
public class doinsertLogAspect {
	
	@Pointcut("bean(sysConumerSerivceImpl)")//切入点也就是各种需要从哪个对象切入
	public void doinsert() {}
	/**由@Around注解描述的方法为一个环绕通知方法，我们可以在此方法内部
	 * 	手动调用目标方法(通过连接点对象ProceedingJoinPoint的proceed方法进行调用)
	 * 	环绕通知：此环绕通知使用的切入点为bean(sysUserServiceImpl)
	 * 	环绕通知特点：
		1)编写：
      a)方法的返回值为Object.
      b)方法参数为ProceedingJoinPoint类型.
      c)方法抛出异常为throwable.
   		2)应用：
      a)目标方法执行之前或之后都可以进行功能拓展
      b)相对于其它通知优先级最高。
		@param jp 为一个连接对象(封装了正在要执行的目标方法信息)
		@return 目标方法的执行结果
	 * @throws Throwable 
	 */

	//新增日志信息
	@Around("doinsert()")  //连接点
	public Object anund(ProceedingJoinPoint jp) throws Throwable {
		
		System.out.println("fffffffffffffffffffffffffffffffffffff");
		//执行时长
		Long start = System.currentTimeMillis();
		log.info("start time {}",start);
		try {
			Object result = jp.proceed();
		Long end = System.currentTimeMillis();
		log.info("end time {}",end);
		Long time = end-start;
		//调用方方法将数据写数据库
		log.info(Thread.currentThread().getName());
		saveLogObject(jp,time);
	
		return result;
		} catch (Throwable e) {
		log.error("eer{}"+e.getMessage());	
			throw e; //注意这是抛出而不是反回
		}	
	}
	@Autowired
	private logService loginserivce;
	
	public void saveLogObject(ProceedingJoinPoint jp,Long time) throws Exception {
	
		//1.获取用户行为日志信息
		//获取目标对象(要执行的那个目标业务对象)类
		Class<?> getcls = jp.getTarget().getClass();
		MethodSignature sim = (MethodSignature) jp.getSignature();
		Method methods = getcls.getDeclaredMethod(sim.getName(), sim.getParameterTypes());
		System.out.println(methods);
		//判断是否是LoginObject的注解值 
		LoginObject falg = methods.getAnnotation(LoginObject.class);
		
		String operation="operation";
		if(falg!=null)
			operation = falg.value();
		
		//用户行为写入
		String method = getcls.getName()+"."+sim.getName();
		//String Params = Arrays.toString(jp.getArgs());//获取普通字符串格式的参数
		//获取json格式的参数	市场现用于较广泛
		String Params = new ObjectMapper().writeValueAsString(jp.getArgs());
		String ip = IPUtil.getIpAddr();
		
		SysLog syslog = new SysLog();
		syslog.setUsername("zhangsan");
		syslog.setIp(ip);
		syslog.setMethod(method);//类名加方法名
		syslog.setOperation(operation);
		syslog.setParams(Params);
		syslog.setTime(time);
		
		
		loginserivce.saveLogObject(syslog);
		log.info(Thread.currentThread().getName());
		
		
//		   new Thread() { //高并发环境下可能很快就会出现内存溢出
//		   public void run() {
//			   sysLogService.saveObject(log);
//		   };
//	   }.start();
	}
	
}
